package secret

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/micro-plat/sas/sas/modules/const/enum"
	"gitee.com/micro-plat/sas/sas/modules/const/models"
	"gitee.com/micro-plat/sas/sas/modules/util"
	per "gitee.com/micro-plat/sas/sas/modules/util/permission"

	"github.com/micro-plat/lib4go/errs"
	"github.com/micro-plat/lib4go/types"
)

//Response 返回信息
type Response struct {
	UID    string `json:"uid"`
	Secret string `json:"secret"`
	Status string `json:"status"`
	Time   string `json:"time"`
}

func newResponse(uid, secret, status string) (*Response, error) {
	decrypt, err := util.AESDecrypt(secret, util.MD5(uid))
	if err != nil {
		return nil, fmt.Errorf("newResponse密钥解密失败:%v", err)
	}

	return &Response{
		UID:    uid,
		Secret: decrypt,
		Status: status,
		Time:   time.Now().Format("2006-01-02 15:04:05"),
	}, nil
}

func newNormalResponse(uid, secret, status string) (*Response, error) {

	return &Response{
		UID:    uid,
		Secret: secret,
		Status: status,
		Time:   time.Now().Format("2006-01-02 15:04:05"),
	}, nil
}

func buildResponse(data types.XMap, secretTypes ...string) (resp *models.Item, err error) {
	resp = &models.Item{
		UID:        data.GetString("uid"),
		EUID:       data.GetString("euid"),
		Time:       time.Now().Format("2006-01-02 15:04:05"),
		ExpireTime: data.GetString("expire_time"),
	}
	aesKey := util.MD5(data.GetString("uid"))
	dbStatus := data.GetInt("status")

	for i := range secretTypes {
		if strings.EqualFold(secretTypes[i], enum.RSAStr) {
			err = fillRsa(data, resp)
			if err != nil {
				return
			}
			continue
		}

		if strings.EqualFold(secretTypes[i], enum.CertStr) {
			err = fillCert(data, resp)
			if err != nil {
				return
			}
			continue
		}

		sType := enum.GetNameByType(secretTypes[i])
		secret := data.GetString(sType)
		decrypt, err := util.AESDecrypt(secret, aesKey)
		if err != nil {
			return nil, fmt.Errorf("buildResponse密钥解密失败:%w", err)
		}
		if !per.Check(dbStatus, enum.GetValueByName(secretTypes[i])) {
			continue
		}
		if strings.EqualFold(decrypt, "") {
			return nil, fmt.Errorf("%s:密钥[%s]未配置", resp.EUID, sType)
		}
		resp.SetSecret(sType, decrypt)
	}
	return
}

func fillRsa(data types.XMap, resp *models.Item) (err error) {
	if !per.Check(data.GetInt("status"), enum.RSA) {
		return
	}

	pubKey := data.GetString("rsa_public_secret")
	if strings.EqualFold(pubKey, "") {
		return fmt.Errorf("%s:密钥[PublicSecret]未配置", resp.EUID)
	}

	pubDecrypt, err := util.AESDecrypt(pubKey, util.MD5(resp.UID))
	if err != nil {
		return fmt.Errorf("RSA公钥解密失败:%v", err)
	}

	priKey := data.GetString("rsa_private_secret")
	if strings.EqualFold(priKey, "") {
		return fmt.Errorf("%s:密钥[PrivateSecret]未配置", resp.EUID)
	}

	priDecrypt, err := util.AESDecrypt(priKey, util.MD5(resp.UID))
	if err != nil {
		return fmt.Errorf("RSA私钥解密失败:%v", err)
	}

	resp.RsaPublicSecret = pubDecrypt
	resp.RsaPrivateSecret = priDecrypt
	resp.RsaType = data.GetString("rsa_type")
	resp.RsaBits = data.GetInt("rsa_bits")
	return
}

func fillCert(data types.XMap, resp *models.Item) (err error) {
	keys := []string{"mer_cert", "spl_cert", "root_cert", "cert_key"}

	mapData := types.XMap{}

	for _, k := range keys {
		v := data.GetString(k)
		if strings.EqualFold(v, "") {
			continue
		}
		plainText, err := util.AESDecrypt(v, util.MD5(resp.UID))
		if err != nil {
			return fmt.Errorf("[%s]解密失败:%v", k, err)
		}

		mapData[k] = plainText
	}

	resp.MerchantCert = mapData.GetString("mer_cert")
	resp.SupplierCert = mapData.GetString("spl_cert")
	resp.RootCert = mapData.GetString("root_cert")
	resp.CertKey = mapData.GetString("cert_key")
	return
}

//RSAResponse RSA返回信息
type RSAResponse struct {
	UID           string `json:"uid"`
	PublicSecret  string `json:"pubilc_secret"`
	PrivateSecret string `json:"private_secret"`
	Status        string `json:"status"`
	Time          string `json:"time"`
	ExpireTime    string `json:"expire_time"`
	PkcsType      string `json:"pkcs_type"`
	Bits          int    `json:"bits"`
}

func newRSAResponse(data types.XMap, status string) (*RSAResponse, error) {
	uid := data.GetString("uid")
	pubDecrypt, err := util.AESDecrypt(data.GetString("rsa_public_secret"), util.MD5(uid))
	if err != nil {
		return nil, fmt.Errorf("RSA公钥解密失败:%v", err)
	}
	priDecrypt, err := util.AESDecrypt(data.GetString("rsa_private_secret"), util.MD5(uid))
	if err != nil {
		return nil, fmt.Errorf("RSA私钥解密失败:%v", err)
	}

	return &RSAResponse{
		UID:           uid,
		PublicSecret:  pubDecrypt,
		PrivateSecret: priDecrypt,
		PkcsType:      data.GetString("rsa_type"),
		Bits:          data.GetInt("rsa_bits"),
		Status:        status,
		Time:          time.Now().Format("2006-01-02 15:04:05"),
		ExpireTime:    data.GetString("expire_time"),
	}, nil
}

func newNormalRSAResponse(uid, pubKey, priKey, status, expireTime, pkcsType string, bits int) (*RSAResponse, error) {

	return &RSAResponse{
		UID:           uid,
		PublicSecret:  pubKey,
		PrivateSecret: priKey,
		PkcsType:      pkcsType,
		Bits:          bits,
		Status:        status,
		Time:          time.Now().Format("2006-01-02 15:04:05"),
		ExpireTime:    expireTime,
	}, nil
}

func buildRSAResponse(data types.XMap) (resp *RSAResponse, err error) {
	pubKey := data.GetString("rsa_public_secret")
	if pubKey == "" {
		err = errs.NewError(enum.ERR_NotGenerate, fmt.Errorf("RSA密钥未生成"))
		return
	}

	uid := data.GetString("uid")
	pubDecrypt, err := util.AESDecrypt(pubKey, util.MD5(uid))
	if err != nil {
		return nil, fmt.Errorf("RSA公钥解密失败:%v", err)
	}

	priKey := data.GetString("rsa_private_secret")
	if priKey == "" {
		err = errs.NewError(enum.ERR_NotGenerate, fmt.Errorf("RSA私钥未生成"))
		return
	}
	priDecrypt, err := util.AESDecrypt(data.GetString("rsa_private_secret"), util.MD5(uid))
	if err != nil {
		return nil, fmt.Errorf("RSA私钥解密失败:%v", err)
	}

	resp = &RSAResponse{
		UID:           uid,
		PublicSecret:  pubDecrypt,
		PrivateSecret: priDecrypt,
		PkcsType:      data.GetString("rsa_type"),
		Bits:          data.GetInt("rsa_bits"),
		Status:        types.DecodeString(per.Check(data.GetInt("status"), enum.RSA), true, "0", "1"),
		Time:          time.Now().Format("2006-01-02 15:04:05"),
		ExpireTime:    data.GetString("expire_time"),
	}
	return
}

type CertResponse struct {
	UID          string `json:"uid"`
	MerchantCert string `json:"mer_cert,omitempty"`
	SupplierCert string `json:"spl_cert,omitempty"`
	RootCert     string `json:"root_cert,omitempty"`
	CertKey      string `json:"cert_key,omitempty"`
	Status       string `json:"status"`
	Time         string `json:"time"`
	ExpireTime   string `json:"expire_time"`
}

func buildCertResponse(data types.XMap) (resp *CertResponse, err error) {
	keys := []string{
		"mer_cert",
		"spl_cert",
		"root_cert",
		"cert_key",
	}
	uid := data.GetString("uid")
	valMap := types.XMap{}
	for _, k := range keys {
		v := data.GetString(k)
		if v == "" {
			continue
		}
		valMap[k], err = util.AESDecrypt(v, util.MD5(uid))
		if err != nil {
			return nil, fmt.Errorf("AESEncrypt %s解密出错:%+v", k, err)
		}
	}

	resp = &CertResponse{
		UID:          uid,
		MerchantCert: valMap.GetString("mer_cert"),
		SupplierCert: valMap.GetString("spl_cert"),
		RootCert:     valMap.GetString("root_cert"),
		CertKey:      valMap.GetString("cert_key"),
		Status:       types.DecodeString(per.Check(data.GetInt("status"), enum.RSA), true, "0", "1"),
		Time:         time.Now().Format("2006-01-02 15:04:05"),
		ExpireTime:   data.GetString("expire_time"),
	}
	return
}
